
#include "../os/os_socket.h"
#include "../include/mystdafx.h"

int os_init_sock_envir()
{
#ifdef WIN32  
	WSADATA wsaData;  
	WORD version = MAKEWORD(2, 0);  
	int ret = WSAStartup(version, &wsaData);//win sock start up  
	if (ret != 0) {  
		return 0;  
	}  
	return 1;
#else
	return 1;
#endif 

}


/* Windows��ʹ��Socket��Ҫ�ȳ�ʼ��һ��*/
#ifdef WIN32
#pragma comment(lib,"ws2_32")
#endif

/* socket ��ַ */
void os_sockaddr_set(os_sockaddr_t* sa, const char* ip, unsigned short port)
{
	sa->iAddr.sin_family = AF_INET;
	sa->iAddr.sin_addr.s_addr = inet_addr(ip);
	sa->iAddr.sin_port = htons(port);
}

void os_sockaddr_setip(os_sockaddr_t* sa, const char* ip)
{
	sa->iAddr.sin_family = AF_INET;
	sa->iAddr.sin_addr.s_addr = inet_addr(ip);
}

void os_sockaddr_setip_n(os_sockaddr_t* sa, unsigned int ip)
{
	sa->iAddr.sin_family = AF_INET;
	sa->iAddr.sin_addr.s_addr = ip;
}

void os_sockaddr_setport(os_sockaddr_t* sa, unsigned short port)
{
	sa->iAddr.sin_family = AF_INET;
	sa->iAddr.sin_port = htons(port);
}

void os_sockaddr_get(os_sockaddr_t* sa,  char* ip, unsigned short* port)
{
	strcpy(ip, inet_ntoa(sa->iAddr.sin_addr));
	*port = ntohs(sa->iAddr.sin_port);
}

void os_sockaddr_getip(os_sockaddr_t* sa, char* ip)
{
	strcpy(ip, inet_ntoa(sa->iAddr.sin_addr));
}

unsigned int os_sockaddr_getip_n(os_sockaddr_t* sa)
{
	return sa->iAddr.sin_addr.s_addr;
}

unsigned short os_sockaddr_getport(os_sockaddr_t* sa)
{
	return ntohs(sa->iAddr.sin_port);
}

/* socket */

int os_sock_setopt_recvtimeout(os_socket_t s, int ms)
{
#ifdef WIN32
	if(socket_setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char*)&ms,sizeof(int)) < 0) 
	{ 
		return  -1;
	} 
	return 0;

#else
	struct timeval tv;
	tv.tv_sec = ms / 1000;
	tv.tv_usec = ms % 1000 * 1000;

	if(socket_setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char*)&tv,sizeof(struct timeval)) < 0) 
	{ 
		return  -1;
	} 
	return 0;
#endif
}

int os_sock_setopt_sendtimeout(os_socket_t s, int ms)
{
#ifdef WIN32
	if(socket_setsockopt(s,SOL_SOCKET,SO_SNDTIMEO,(char*)&ms,sizeof(int)) < 0) 
	{ 
		return  -1;
	} 
	return 0;
#else
	struct timeval tv;
	tv.tv_sec = ms / 1000;
	tv.tv_usec = ms % 1000 * 1000;

	if(socket_setsockopt(s,SOL_SOCKET,SO_SNDTIMEO,(char*)&tv,sizeof(struct timeval)) < 0) 
	{ 
		return  -1;
	} 
	return 0;

#endif

}
int os_sock_getopt_recvtimeout(os_socket_t s)
{
#ifdef WIN32
	int args = 0;
	socklen_t args_len = sizeof(int);
	if(socket_getsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char*)&args, &args_len) < 0) 
	{ 
		return  -1;
	} 

	return args;
#else
	struct timeval tv;
	socklen_t tv_len = sizeof(struct timeval);
	if(socket_getsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char*)&tv, &tv_len) < 0) 
	{ 
		return  -1;
	} 

	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
#endif
}

int os_sock_getopt_sendtimeout(os_socket_t s)
{
#ifdef WIN32
	int args = 0;
	socklen_t args_len = sizeof(int);
	if(socket_getsockopt(s,SOL_SOCKET,SO_SNDTIMEO,(char*)&args, &args_len) < 0) 
	{ 
		return  -1;
	} 

	return args;
#else

	struct timeval tv;
	socklen_t tv_len = sizeof(struct timeval);
	if(socket_getsockopt(s,SOL_SOCKET,SO_SNDTIMEO,(char*)&tv, &tv_len) < 0) 
	{ 
		return  -1;
	} 

	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
#endif
}

int os_sock_ioctl_setnoblockio(os_socket_t s)
{
	// is error for epoll
#ifdef WIN32
	unsigned   long   args =  1;
	if( socket_ioctl(s,   FIONBIO,   (unsigned   long*)&args) < 0)
	{
		return -1;
	}
	return 0;
#else
	int flags;

	flags = fcntl(s, F_GETFL, 0);
	if (flags == -1)
	{
		return -1;
	}
	flags |= O_NONBLOCK;
	flags = fcntl(s, F_SETFL, flags);
	if (flags == -1)
	{
		return -1;
	}
	return 0;
#endif
}

int os_sock_setopt_reuseaddr(os_socket_t s, int reuse)
{
	int opt = reuse ? 1: 0;
	socklen_t len = sizeof(opt);
	if (socket_setsockopt(s, SOL_SOCKET,SO_REUSEADDR,(char*)&opt,len) < 0)
	{
		return -1;
	}

	return 0;
}

int os_sock_setopt_keeplive(os_socket_t s, int keeplive)
{
	int opt = keeplive ? 1: 0;
	socklen_t len = sizeof(opt);
	if (socket_setsockopt(s, SOL_SOCKET,SO_KEEPALIVE,(char*)&opt,len) < 0)
	{
		return -1;
	}

	return 0;
}

int os_sock_getpeeraddr(os_socket_t s, os_sockaddr_t* addr) 
{
	socklen_t len = sizeof(addr);
	if(getpeername(s, (struct sockaddr*)addr, &len) < 0)
	{
		return -1;
	}
	return 0;
}

int os_sock_getlocaladdr(os_socket_t s, os_sockaddr_t* addr) 
{
	socklen_t len = sizeof(addr);
	if(getsockname(s, (struct sockaddr*)addr, &len) < 0) 
	{
		return -1;
	}
	return 0;
}

/////////////////////////////////////////////////////////////
/* tcp socket */
int os_tcpsock_open(os_socket_t* s, int reuse)
{
	*s = socket_open(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if((int)*s < 0)
	{
		return -1;
	}

	os_sock_setopt_reuseaddr(*s, reuse);
	return 0;
}

int os_tcpsock_openat(os_socket_t* s, const os_sockaddr_t* sa, int reuse)
{
	if(os_tcpsock_open(s, reuse) < 0)
	{
		return -1;
	}
	if (socket_bind(*s, (struct sockaddr*) sa, sizeof(struct sockaddr_in)) < 0)
	{
		socket_close(*s);
		*s = -1;
		return -1;
	}
	return 0;
}

void os_tcpsock_close(os_socket_t* s)
{
	if((int)*s >= 0)
	{
		shutdown(*s, 2);
		socket_close(*s);
		*s = -1;
	}
}

int os_tcpsock_listen(os_socket_t s, int backlog)
{
	if(socket_listen(s, backlog) < 0)
	{
		return -1;
	}
	return 0;
}

int os_tcpsock_accept(os_socket_t s, os_socket_t * peer)
{
	struct sockaddr_in addr;
	socklen_t addr_len = sizeof(struct sockaddr_in);
	*peer= socket_accept( s, (struct sockaddr*)&addr, &addr_len );

	if ((int) *peer < 0)
	{
		return -1;
	}

	return 0;
}

int os_tcpsock_connect(os_socket_t s, const os_sockaddr_t* sa)
{
	if(socket_connect(s, (struct sockaddr*) sa, sizeof(struct sockaddr)) < 0)
	{
		return -1;
	}
	return 0;
}

int os_tcpsock_send(os_socket_t s, const void* buf, int len, int nFlags)
{
	int n = socket_send(s, (const char*) buf, len, nFlags);
	return n;
}

int os_tcpsock_recv(os_socket_t s, void* buf, int len, int nFlags)
{
	int n = socket_recv(s, (char*) buf, len, nFlags);
	return n;
}

/////////////////////////////////////////////////////////////
/* udp socket */
int os_udpsock_open(os_socket_t* s, int reuse )
{
	*s = socket_open(	AF_INET, 	SOCK_DGRAM, 	0 );
	if((int)*s < 0)
	{
		return -1;
	}

	os_sock_setopt_reuseaddr(*s, reuse);
	return 0;
}

int os_udpsock_openat(os_socket_t* s, const os_sockaddr_t* sa, int reuse)
{
	if(os_udpsock_open(s, reuse) < 0)
	{
		return -1;
	}
	if (socket_bind(*s, (struct sockaddr*) sa, sizeof(struct sockaddr_in)) < 0)
	{
		socket_close(*s);
		*s = -1;
		return -1;
	}
	return 0;
}

void os_udpsock_close(os_socket_t* s)
{
	if((int)*s >= 0)
	{
		shutdown(*s, 2);
		socket_close(*s);
		*s = -1;
	}
}

int os_udpsock_sendto(os_socket_t s, const void* buf, int len, const os_sockaddr_t*  peer)
{
	int  addr_len = sizeof(struct sockaddr_in);
	int n = socket_sendto(s, (const char*) buf, len, 0, (struct sockaddr*) peer, addr_len);
	if(n < 0)
	{
		return -1;
	}

	return 0;
}

int os_udpsock_recvfrom(os_socket_t s, void* buf, int max_len, os_sockaddr_t* peer)
{
	// �������
	socklen_t  addr_len = sizeof(struct sockaddr_in);
	int n = socket_recvfrom(s, (char*) buf, max_len, 0, (struct sockaddr*) &peer, &addr_len);
	if(n < 0)
	{
		return -1;
	}

	return n;
}

/////////////////////////////////////////////////////////////
/* multicast socket */
int os_mcast_open(os_socket_t* s, const char* mcast_ip, int port, const char* local_ip)
{
	struct ip_mreq _mreq;
	struct sockaddr_in addr;

	os_socket_t s_new = -1;
	s_new = socket(	AF_INET, SOCK_DGRAM, 0 );
	if((int)s_new< 0)
	{
		return -1;
	}

	// һ����Ҫ
	if(os_sock_setopt_reuseaddr(s_new, 1) < 0)
	{
		socket_close(s_new);
		s_new = -1;
		return -1;
	}

	// ��ip
	addr.sin_family = AF_INET;
#ifdef WIN32
	addr.sin_addr.s_addr = inet_addr(local_ip);
#else
	addr.sin_addr.s_addr = inet_addr(mcast_ip);
#endif
	addr.sin_port = htons(port);
	if (socket_bind(s_new, (struct sockaddr*) &addr, sizeof(struct sockaddr)) < 0)
	{
		socket_close(s_new);
		s_new = -1;
		return -1;
	}

	// ע���鲥

	_mreq.imr_multiaddr.s_addr = inet_addr(mcast_ip); 
	_mreq.imr_interface.s_addr = inet_addr(local_ip); 
	if (setsockopt(s_new, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&_mreq, sizeof(_mreq)) < 0)
	{ 
		socket_close(s_new);
		s_new = -1;
		return -1;
	}

	*s = s_new;

	return 0;
}

void os_mcast_close(os_socket_t* s)
{
	if((int)*s >= 0)
	{
		shutdown(*s, 2);
		socket_close(*s);
		*s = -1;
	}
}

int os_mcast_recvfrom(os_socket_t s, void* buf, int max_len, const os_sockaddr_t* peer)
{
	// �������
	socklen_t  addr_len = sizeof(struct sockaddr_in);
	int n = socket_recvfrom(s, (char*) buf, max_len, 0, (struct sockaddr*) peer, &addr_len);
	if(n < 0)
	{
		return -1;
	}

	return n;
}
